# coding=utf-8
from datetime import date, timedelta, datetime

from flask import g
from wechatpy.replies import ArticlesReply

from . import app
from .exceptions import AabException
from .handlers_auth import create_user, ensure_group
from .handlers_status import do_query_state, update_state
from .model import User, Roles, db, DailyState, Group
from .settings import config
from .utils import hash_password

_HANDLERS = dict()
_HANDLE_NAMES = []
UNKNOWN_PEOPLE_ERROR = 'How dare you!!!'
LOG = app.logger
WEEKDAYS = [u'星期一', u'星期二', u'星期三', u'星期四', u'星期五', u'星期六', u'星期日']
ROLE_DICT = {
    Roles.USER: '组员',
    Roles.GROUP_MANAGER: '组长',
    Roles.ADMIN: 'Boss'
}
DATE_FORMAT = '%Y-%m-%d'

DATE_TO_DELTA = {
    '前天': timedelta(days=-2),
    '昨天': timedelta(days=-1),
    '今天': timedelta(days=0),
    '明天': timedelta(days=1),
    '后天': timedelta(days=2)
}


def parse_day(day_string, default_today=True):
    if not day_string and default_today:
        return date.today()

    delta = DATE_TO_DELTA.get(day_string, None)
    if delta is not None:
        return date.today() + delta
    else:
        return datetime.strptime(day_string, DATE_FORMAT)


def format_help(role):
    desc_list = [_HANDLERS[name].desc for name in _HANDLE_NAMES]
    desc_list = [desc.help() for desc in desc_list if desc.can_use(role) and desc.need_user]
    cmd_list = '\n\n'.join(desc_list)
    return '可用命令包括：\n\n{}'.format(cmd_list)


def handle_request(msg, cmd, *args):
    try:
        g.weixin_id = msg.source
        user = User.query.filter_by(weixin_id=msg.source).scalar()

        handler = _HANDLERS.get(cmd, None)
        if handler is None:
            if user is None:
                return UNKNOWN_PEOPLE_ERROR + '!'
            else:
                return ArticlesReply(message=g.message, articles=[
                    {
                        'title': '主页',
                        'description': '未知命令：{}，可尝试使用官网界面操作'.format(cmd),
                        'url': 'https://aab.cadl.name'
                    }
                ])

        g.user = user
        if not handler.desc.check(user):
            return UNKNOWN_PEOPLE_ERROR + '!!'

        r = handler(*args)
        if r is None:
            return u'已完成{}： {}'.format(cmd, u' '.join(args))
        elif r == u'':
            return u'[结果为空]'
        else:
            return r
    except AabException as ex:
        return 'ERROR[#{}]: {}'.format(ex.status_code, ex.message)
    except Exception as ex:
        return u'ERROR: {}'.format(ex)


class CommandDesc:
    def __init__(self, name, arg_desc, desc, roles, need_user=True):
        self.name = name
        self.arg_desc = arg_desc
        self.desc = desc
        self.roles = roles
        self.need_user = need_user

    def can_use(self, role):
        if self.roles is None:
            return True

        return role in self.roles

    def help(self):

        result = ''
        if self.desc:
            result += '# {}\n'.format(self.desc)
        result += '{} {}'.format(self.name, self.arg_desc)
        return result

    def check(self, user):
        if not self.need_user:
            return True

        if not user:
            return False

        return self.can_use(user.role)


def wx_command(name, arg_desc, desc=None, roles=None, need_user=True):
    def decorator(fn):
        fn.desc = CommandDesc(name, arg_desc, desc, roles, need_user)
        _HANDLERS[name] = fn
        _HANDLE_NAMES.append(name)
        return fn

    return decorator


@wx_command('申请', '<编号> <密码> <暗号，请向管理员索取>', '绑定系统账号', need_user=False)
def wx_on_request(number, password, register_secret):
    user = User.query.filter_by(number=number).scalar()
    if user is None:
        LOG.debug('user not found')
        return UNKNOWN_PEOPLE_ERROR + '!!!'

    if user.weixin_id == g.weixin_id:
        return u'您早已是一名光荣的革命小将了'

    if hash_password(user.salt + password) != user.password:
        LOG.debug('password error')
        return UNKNOWN_PEOPLE_ERROR + '!!!!'

    if register_secret != config.weixin.register_secret:
        LOG.debug('register secret wrong')
        return UNKNOWN_PEOPLE_ERROR + '!!!!!'

    other_user = User.query.filter_by(weixin_id=g.weixin_id).scalar()
    if other_user is not None:
        other_user.weixin_id = None

    user.weixin_id = g.weixin_id
    db.session.commit()
    return u'恭喜您称为一名光荣的革命小将'


@wx_command('重置密码', '<用户编号>', '重置某个用户的密码为用户编号', roles=[Roles.ADMIN])
def wx_reset_password(user_number):
    target_user = User.query.filter_by(number=user_number).scalar()
    if target_user is None:
        return '用户不存在'

    target_user.password = hash_password(target_user.salt + target_user.number)
    db.session.commit()


@wx_command('谁没填', '[日期]', '查看当前组有谁没有及时更新个人状态信息，日期格式为2020-02-02或者昨天、今天、明天')
def wx_query_unfilled(day=None):
    if g.user.role == Roles.ADMIN:
        users = User.query.filter(User.role != Roles.ADMIN).order_by(User.group_id).order_by(User.number)
    else:
        users = User.query.filter_by(group_id=g.user.group_id).order_by(User.number)

    day = parse_day(day)
    result = []
    for user in users:
        daily_state = DailyState.query.filter_by(user=user, day=day).scalar()
        if daily_state is None:
            if g.user.role == Roles.ADMIN:
                result.append('{}({})'.format(user.number, user.group.name))
            else:
                result.append(user.number)

    if len(result) == 0:
        return u'全填好了'
    else:
        return '这些人没填：{}'.format('，'.join(result))


@wx_command('帮助', '', '获取帮助信息')
def help_message():
    role = g.user.role
    return format_help(role)


@wx_command('添加用户', '<用户编号> <组名> [角色]', '添加用户，默认组员角色，可选角色为[User, GroupManager, Admin]', roles=[Roles.ADMIN])
def wx_add_user(user_number, group, role=Roles.USER):
    create_user(user_number, group, role)
    db.session.commit()


@wx_command('改组', '<用户编号> <新组名>', '更改用户所在组', roles=[Roles.ADMIN])
def wx_change_group(user_number, new_group):
    user = User.query.filter_by(number=user_number).scalar()
    if user is None:
        return 'ERROR: 用户不存在'

    group = ensure_group(new_group)
    user.group = group
    db.session.commit()


@wx_command('删除用户', '<用户编号>', '删除用户，只能删除没有更新任何信息的用户', roles=[Roles.ADMIN])
def wx_delete_user(user_number):
    user = User.query.filter_by(number=user_number).scalar()
    if user:
        db.session.delete(user)
    db.session.commit()


@wx_command('报体温', '<早晨体温> <中午体温> <晚上体温> [相关人员体温列表，空格分开]', '填写当日上午应当填的体温')
def wx_update_temperature(t1, t2, t3, *t_list):
    now = datetime.now()
    if now.hour >= 18:
        raise AabException(400, "只能在18点之前更新前一日体温")
    return update_temperature(now.date(), t1, t2, t3, *t_list)


@wx_command('预报体温', '<早晨体温> <中午体温> <晚上体温> [相关人员体温列表，空格分开]', '填写次日上午应当填的体温')
def wx_update_tomorrow_temperature(t1, t2, t3, *t_list):
    now = datetime.now()
    if now.hour < 18:
        raise AabException(400, "只能在18点之后更新当日体温")

    day = now.date() + timedelta(days=1)
    return update_temperature(day, t1, t2, t3, *t_list)


@wx_command('注销', '', '解除微信与系统账号的绑定')
def wx_unregister():
    g.user.weixin_id = None
    db.session.commit()


def update_temperature(day, t1, t2, t3, *t_list):
    user = g.user
    state = do_query_state(user, for_update=True)
    if state is None:
        return 'ERROR: 从未填写过任何状态信息。请先在Web界面上填写完整信息后，再每日通过该接口更新体温'

    state['temperature_morning'] = float(t1)
    state['temperature_middle'] = float(t2)
    state['temperature_night'] = float(t3)

    persons = state.get('persons', [])
    more = min(len(t_list), len(persons))
    for i in range(more):
        persons[i]['temperature'] = float(t_list[i])

    update_state(user, state, day)
    db.session.commit()


@wx_command('我是谁', '', '查看当前用户信息')
def who_am_i():
    user = g.user
    return '我是[{}]，在组[{}]，角色是[{}]'.format(user.number, user.group.name, ROLE_DICT.get(user.role, user.role))
